using System.Collections.Generic;

using FineCollection.Intf;


namespace FineCollection.Const
{
    /// <summary>
    /// Immutable set of exactly one item. 
    /// This item must be not null.
    /// </summary>
    /// <typeparam name="T">type of the item.</typeparam>
    public class ConstOne<T> : RSet<T>, RRandomList<T>
    {

        public IEqualityComparer<T> Equator { get; private set; }


        #region STATE

        /// <summary>
        /// The single item.
        /// </summary>
        internal T item;

        #endregion


        #region CONSTRUCTOR

        /// <summary>
        /// Trivial constructor.
        /// </summary>
        /// <param name="item">the single item (not null).</param>
        public ConstOne(T item)
        {
            this.Equator = EqualityComparer<T>.Default;
            this.item = item;
        }

        /// <summary>
        /// Trivial constructor.
        /// </summary>
        /// <param name="item">the single item (not null).</param>
        /// <param name="equator">custom equator.</param>
        public ConstOne(T item, IEqualityComparer<T> equator)
        {
            this.Equator = equator;
            this.item = item;
        }

        #endregion



        public bool IsEmpty
        {
            get { return false; }
        }

        public bool IsNotEmpty
        {
            get { return true; }
        }

        public int Count
        {
            get { return 1; }
        }

        public bool Contains(T item)
        {
            return Equator.Equals(this.item, item);
        }


        public RIterator<T> TakeIterator()
        {
            return new IteratorOfOne<T>(this);
        }


        System.Collections.Generic.IEnumerator<T> System.Collections.Generic.IEnumerable<T>.GetEnumerator()
        {
            return new IteratorOfOne<T>(this);
        }


        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return new IteratorOfOne<T>(this);
        }


        public T First
        {
            get { return item; }
        }

        public T Last
        {
            get { return item; }
        }

        public int FirstIndex
        {
            get { return 1; }
        }


        public T this[int index]
        {
            get
            {
                if (index == 1)
                    return item;
                else
                    throw new IndexOutOfBoundsException(index, 1, 1);
            }
        }


        public int LastIndex
        {
            get { return 1; }
        }



        #region ITERATOR CLASS

        internal class IteratorOfOne<TT> : RIterator<TT>,
                                           System.Collections.Generic.IEnumerator<TT>,
                                           System.IDisposable
        {
            protected readonly ConstOne<TT> one;
            protected sbyte state; 

            internal IteratorOfOne(ConstOne<TT> one)
            {
                this.one = one; 
                this.state = -1;
            }

            internal IteratorOfOne(ConstOne<TT> one, sbyte state)
            {
                this.one = one;
                this.state = state;
            }

            public void Reset()
            {
                state = -1;
            }

            public bool Next()
            {
                state++;
                return state == 0;
            }

            public TT Current
            {
                get
                {
                    if (state == 0)
                        return one.item;
                    else
                        throw new IndexOutOfBoundsException(state, 1, 1);
                }
            }


            public sbyte Where
            {
                get { return state; }
            }


            public virtual RIterator<TT> Clone()
            {
                return new IteratorOfOne<TT>(one, state);
            }


            bool System.Collections.IEnumerator.MoveNext()
            {
                if (Where < +1)
                    return Next(); // shifts the iterator
                else
                    return false;
            }

            object System.Collections.IEnumerator.Current
            {
                get { return Current; }
            }

            void System.IDisposable.Dispose()
            {
                // do nothing
            }

            public override string ToString()
            {
                switch(state)
                {
                    case -1:
                        return "begin";
                    case 0:
                        return "1->" + one.item.ToString();
                    case +1:
                        return "end";
                    default:
                        return "undefined";

                }
            }
        }

        #endregion



        public override string ToString()
        {
            return '{' + item.ToString() + '}';
        }
    }
}